package com.ybkj.daijia.server.exception;

import com.ybkj.daijia.server.interceptors.MethodInterceptor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;

@ControllerAdvice
@Slf4j
public class ExceptionHandlerController implements InitializingBean {

    public static final String DEFAULT_ERROR_VIEW = "500";
    private String os = "";
    private Logger logger = LoggerFactory.getLogger(ExceptionHandlerController.class);
    @Autowired
    private HttpServletRequest request;

    @PostConstruct
    public void init() {
        if (os.indexOf("windows") != -1) {
            return;
        }
    }

    @ExceptionHandler(value = Exception.class)
    public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        // 如果异常使用了ResponseStatus注解，那么重新抛出该异常，Spring框架会处理该异常。
        if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
            throw e;
        }
        String exceptionStr = getExceptionStr(e);
        if (os.indexOf("windows") != -1) {
           if (log.isErrorEnabled()) {
               log.error(com.ybkj.daijia.constant.DateConstant.DATE_TIME.format(new Date()) + " {}", exceptionStr);
           }
        } else {
            if (logger.isErrorEnabled() && !(e instanceof NoPermissionException)) {
                logger.error(exceptionStr);
            }

        }
        if (checkResult()) {
            return createResult(exceptionStr, e);
        }

        // 否则创建ModleAndView，处理该异常。
        ModelAndView mav = new ModelAndView();
        mav.addObject("exception", exceptionStr);
        mav.addObject("url", req.getRequestURL());
        mav.setViewName(DEFAULT_ERROR_VIEW);
        return mav;
    }

    public String getExceptionStr(Exception e) {
        Map<String, String[]> paramMap = request.getParameterMap();
        String paramStr = "";
        String headerStr = "";
        if (paramMap.size() > 0) {
            StringBuilder sb = new StringBuilder();
            for (String key : paramMap.keySet()) {
                sb.append(key).append(":").append(Arrays.toString(paramMap.get(key))).append(",");
            }
            if (sb.length() > 0) {
                sb.deleteCharAt(sb.length() - 1);
            }
            paramStr = sb.toString();
        } else {
            //流形式提交
        }
        Enumeration headerNames = request.getHeaderNames();
        if (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement().toString();
            headerStr += headerName + ":" + request.getHeader(headerName) + ",";
        }
        String eString = e.toString();
        StringBuffer sb = new StringBuffer();
        sb.append(request.getRequestURI()).append("\n");
        sb.append(request.getMethod()).append("\n");
        sb.append("param:").append(paramStr).append("\n");
        sb.append("hreadStr:").append(headerStr).append("\n");
        Writer exceptionStr = new StringWriter();
        PrintWriter printWriter = new PrintWriter(exceptionStr);
        e.printStackTrace(printWriter);
        sb.append(exceptionStr).append("\n");
        return sb.toString();
    }

    public boolean checkResult() {
        Method method = MethodInterceptor.getMethod();
        if (method != null) {
            if (method.isAnnotationPresent(ResponseBody.class)) {
                return true;
            }
            Class resultType = method.getReturnType();
            if (resultType.isAnnotationPresent(ResponseBody.class)) {
                return true;
            }
        }
        return false;
    }

    public ModelAndView createResult(String exceptionStr, Exception e) {
        ModelAndView mv = new ModelAndView(new MappingJackson2JsonView());
        if (e instanceof CanThrowToUserException) {
            CanThrowToUserException e1 = (CanThrowToUserException) e;
            mv.addObject("code", e1.getCode());
            mv.addObject("message", e1.getMessage());
            mv.addObject("success", false);
        }else {
            mv.addObject("code", -1);
            mv.addObject("message", "内部服务器错误");
            mv.addObject("success", false);
        }
        if ("debug".equals(request.getHeader("debug"))) {
            mv.addObject("debug", exceptionStr);
        }
        return mv;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        os = System.getProperty("os.name").toLowerCase();
    }
}
